Inside Macintosh: Memory

Previous | Chapter Top | Chapter Contents | Next

Allocating Blocks of Memory

As you have seen, a key element of the memory-management scheme presented in this chapter is to disallow any nonessential memory allocation requests that would deplete the memory cushion. In practice, this means that, before calling NewHandle , NewPtr , or another function that allocates memory, you should check that the amount of space remaining after the allocation, if successful, exceeds the size of the memory cushion.

An easy way to do this is never to allocate memory for nonessential tasks by calling NewHandle or NewPtr directly. Instead call a function such as NewHandleCushion , defined in Listing 1-6 , or NewPtrCushion , defined in Listing 1-7 .

Listing 6 Allocating relocatable blocks

FUNCTION NewHandleCushion (logicalSize: Size): Handle;
BEGIN
    IF NOT IsMemoryAvailable(logicalSize) THEN
        NewHandleCushion := NIL
    ELSE
        BEGIN
            SetGrowZone(NIL);                   {remove grow-zone function}
            NewHandleCushion := NewHandleClear(logicalSize);
            SetGrowZone(@MyGrowZone);           {install grow-zone function}
        END;
END;

The NewHandleCushion function first calls IsMemoryAvailable to determine whether allocating the requested number of bytes would deplete the memory cushion. If so, NewHandleCushion returns NIL to indicate that the request has failed. Otherwise, if there is indeed sufficient space for the new block, NewHandleCushion calls NewHandleClear to allocate the relocatable block. Before calling NewHandleClear , however, NewHandleCushion disables the grow-zone function for the application heap. This prevents the grow-zone function from releasing any emergency memory reserve your application might be maintaining. See "Defining a Grow-Zone Function" for details on grow-zone functions.

You can define a function NewPtrCushion to handle allocation of nonrelocatable blocks, as shown in Listing 1-7 .

Listing 7 Allocating nonrelocatable blocks

FUNCTION NewPtrCushion (logicalSize: Size): Handle;
BEGIN
    IF NOT IsMemoryAvailable(logicalSize) THEN
        NewPtrCushion := NIL
    ELSE
        BEGIN
            SetGrowZone(NIL);                   {remove grow-zone function}
            NewPtrCushion := NewPtrClear(logicalSize);
            SetGrowZone(@MyGrowZone);           {install grow-zone function}
        END;
END;

The functions NewHandleCushion and NewPtrCushion allocate prezeroed blocks in your application heap. You can easily modify those functions if you do not want the blocks prezeroed.

Listing 1-8 illustrates a typical way to call NewPtrCushion .

Listing 8 Allocating a dialog record

FUNCTION GetDialog (dialogID: Integer): DialogPtr;
VAR
    myPtr: Ptr;                         {storage for the dialog record}
BEGIN
    myPtr := NewPtrCushion(SizeOf(DialogRecord));
    IF MemError = noErr THEN
        GetDialog := GetNewDialog(dialogID, myPtr, WindowPtr(-1))
    ELSE
        GetDialog := NIL;               {can't get memory}
END;

When you allocate memory directly, you can later release it by calling the DisposeHandle and DisposePtr procedures. When you allocate memory indirectly by calling a Toolbox routine, there is always a corresponding Toolbox routine to release that memory. For example, the DisposeWindow procedure releases memory allocated with the NewWindow function. Be sure to use these special Toolbox routines instead of the generic Memory Manager routines when applicable.


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next